#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "ulog/ulog.h"
#include "aos/hal/uart.h"
#include "uart_packet.h"
#include "aos/kernel.h"

#include "if_v.h"

#define TAG "UART-PACKET:"
uint8_t  printf_hex = 1;

aos_timer_t     g_uart_rx_timer;
int rx_timeout_flag=0;

#define H2M_PACKET_MAGIC_LEN 2
#if defined SENSETIME_PROTOCOL_ENABLE
#define H2M_PACKET_HEADER_LEN 3
#else
#define H2M_PACKET_HEADER_LEN 5
#endif
#define H2M_PACKET_HEADER_TOTAL_LEN (H2M_PACKET_MAGIC_LEN + H2M_PACKET_HEADER_LEN)

extern data_flow_func_control_t g_ifv_flow_cfg; 

void store_le_uint32(uint8_t *addr, uint32_t value) /* big endian */
{
    addr[0] = value >> 24;
    addr[1] = (value >> 16) & 0xff;
    addr[2] = (value >> 8) & 0xff;
    addr[3] = value & 0xff;
}

void store_le_uint16(uint8_t *addr, uint16_t value) /* big endian */
{
    addr[0] = value >> 8; 
    addr[1] = value & 0xff;
}

void dump_le_uint32(uint8_t *addr, uint32_t *value)   /* big endian to little endian*/
{
	*value = 0;
    *value = addr[0] << 24;
	*value |= addr[1] << 16;
	*value |= addr[2] << 8;
	*value |= addr[3];
}

uint32_t dump_uint32(uint8_t *addr)   /*little endian to little endian*/
{
	uint32_t value = 0;
    value = addr[3] << 24;
	value |= addr[2] << 16;
	value |= addr[1] << 8;
	value |= addr[0];
	return value;
}


void dump_le_uint16(uint8_t *addr, uint16_t *value) /* big endian to little endian*/
{
	*value = 0;
	*value = addr[0]<<8;
	*value |= addr[1];
}


uint8_t get_check_parity(uint8_t *buf, uint32_t size)
{
	uint32_t i;
	uint8_t tmp_parity = 0;
	for(i = 0; i < size; i++){
		tmp_parity = tmp_parity ^ buf[i];
	}
	return tmp_parity;
}

uint8_t get_check_sum(uint8_t *buf, uint32_t size)
{
	uint32_t i;
	uint8_t tmp_sum = 0;
	for(i = 0; i < size; i++){
		tmp_sum = tmp_sum + buf[i];
	}
	return tmp_sum;
}

int m2h_register_from_uart_ack(uart_dev_t *uart,uint32_t result,uint32_t id)
{
	uint8_t sendData[13] = {0xEF, 0xAA, 0x14, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0x15};

	sendData[3] = result;
	//memcpy(&sendData[6],&id,sizeof(uint32_t));
	store_le_uint32((uint8_t *)&sendData[8], id);
	sendData[12] = get_check_sum(&sendData[2], 10);
	printf("id %02x %02x %02x %02x checksum %02x \n",sendData[8],sendData[9],sendData[10],sendData[11],sendData[12]);
	
	//if(1 == printf_hex)
	{
		hal_uart_send(uart, sendData, 13, 100);
	}

	printf("m2h_register_from_uart_ack *****************************\n");
	
	return 0;
}

int m2h_request_id_ack(uart_dev_t *uart,uint32_t id)
{
	uint8_t sendData[12] = {0xEF, 0xAA, 0xB1, 0, 0, 0, 0x04, 0, 0, 0, 0, 0xB5};

	store_le_uint32((uint8_t *)&sendData[7],id);
	sendData[11] = get_check_sum(&sendData[2], 9);
	printf("id %02x %02x %02x %02x checksum %02x \n",
        sendData[7], sendData[8], sendData[9], sendData[10], sendData[11]);
	
	//if(1 == printf_hex)
	{
		hal_uart_send(uart, sendData, 12, 100);
	}

	printf("m2h_request_id_ack *****************************\n");
	
	return 0;
}

int m2h_msg_send(uart_dev_t *uart, uint8_t msgid, uint32_t size, uint8_t *data)
{
	uint8_t head[H2M_PACKET_HEADER_TOTAL_LEN] = {0xEF, 0xAA, 0, 0, 0, 0, 0};
	head[2] = msgid;
	if(g_ifv_flow_cfg.sensetime_protocol_enable){
		store_le_uint16(&head[3], size);
	}else{
		store_le_uint32(&head[3], size);
	}
	
	uint8_t checksum_head = get_check_sum(&head[2], H2M_PACKET_HEADER_LEN);
	uint8_t checksum_data = get_check_sum(data, size);
	uint8_t checksum = checksum_head + checksum_data;

	char printf_buf[100];
	if(1 == printf_hex)
	{
		hal_uart_send(uart, head, H2M_PACKET_HEADER_TOTAL_LEN, 100);
		if(size > 0){
			hal_uart_send(uart, data, size, 100);
		}
		hal_uart_send(uart, &checksum, 1, 100);
	}
	else
	{
		sprintf(printf_buf, "%02x,%02x,%02x,%02x,%02x,", head[0], head[1],head[2], head[3],head[4]);
		for(int i=0; i< size; i++)
		{
			sprintf(printf_buf+15+i*3, "%02x,", data[i]);
		}
		sprintf(printf_buf+15+size*3, "%02x\r\n", checksum);
		hal_uart_send(uart, printf_buf, (H2M_PACKET_HEADER_LEN+size)*3+4, 100);
	}

	return 0;
}

int app_uart_recv(uart_dev_t *uart, uint8_t *inbuf, int size, uint32_t timeout)
{
    int32_t  ret       = 0;
    uint32_t recv_size = 0;

    ret = hal_uart_recv_II(uart, inbuf, size, &recv_size, timeout);
    if ((ret == 0) && (recv_size == size)) {
        return recv_size;
    } else {
        return 0;
    }
}

extern uint32_t enroll_from_uart_busy_flag;
extern int aie_vis_detect_enable;
extern uint8_t isp_rgb_enable_flag;

void uart_rx_timer_process(){
    rx_timeout_flag=1;
    //printf("rx timer %d.\n",rx_timeout_flag);

}

int h2m_msg_recv(uart_dev_t *uart, uint8_t *inbuf, int *rece_size)
{
    int ret=0;
	static int errCode = 0;
// SyncWord	 MsgID	 Size	  Data	   ParityCheck
// 2 bytes  1 byte	 4 bytes  N bytes  1 byte
	if(app_uart_recv(uart, inbuf, 2, 100) != 2) //SyncWord
	{
		if(errCode)
		{
			printf("warning! please resend the uart cmd! \n");
			errCode = 0;
			return 5;
		}
		else{
			return 0;
		}	
	}
    
    if(inbuf[0] != 0xEF || inbuf[1] != 0xAA)
    {
		errCode = 4;
        return 4;
    }

	if(enroll_from_uart_busy_flag == 1)
		aos_msleep(10);
	
	//printf("syncword ok\n");
    aos_timer_new_ext(&g_uart_rx_timer, uart_rx_timer_process, NULL,50, 0, 1);                   
    rx_timeout_flag=0;
	do{
        ret = app_uart_recv(uart, inbuf, H2M_PACKET_HEADER_LEN, 10);
        aos_msleep(1);
    }while((ret != H2M_PACKET_HEADER_LEN) && (!rx_timeout_flag) );
    //printf("ret=%d\n",ret);
    aos_timer_stop(&g_uart_rx_timer);
    aos_timer_free(&g_uart_rx_timer);
    if( ret != H2M_PACKET_HEADER_LEN ) 
    {
      printf("cmd or length %d error \n",ret);
      errCode = 1;
      return 1;
    }

	uint8_t msgid = inbuf[0];
	uint32_t msg_data_size = 0, remain = 0;
	if(g_ifv_flow_cfg.sensetime_protocol_enable){
		if(inbuf[1] == 0)
		{
			dump_le_uint16(&inbuf[1], (uint16_t *)&msg_data_size);
			msg_data_size += 1; //check sum
		}
		else
		{
			dump_le_uint16(&inbuf[0], (uint16_t *)&msg_data_size);
		}
	}
	else{
		dump_le_uint32(&inbuf[1], &msg_data_size);
    
		msg_data_size += 1; //check sum
	}
	
    
	remain = msg_data_size;

	//TODO: modify buf size 
#define UART_RECV_PER 100
	int offset = H2M_PACKET_HEADER_LEN;
    int to_read;
                                  
	if(msg_data_size > 100*1024){
		printf("pic len beyond the max ! no ACK! \n");
		errCode = 2;
		return 2;
	}

	if(msgid == MID_ENROLL_UART){
		printf("pic len: %d \n",msg_data_size);
		isp_rgb_enable_flag = 0;
		aie_vis_detect_enable = 0;
	}
		
	if(msg_data_size > UART_RECV_PER)
		aos_msleep(10);

    while (remain > 0) 
    {
        to_read = remain > UART_RECV_PER ? UART_RECV_PER : remain;
        if(app_uart_recv(uart, inbuf+offset, to_read, 200) != to_read)
        {
            printf("recv error: %d \n", to_read);
			errCode = 3;
            return 3;
        }
		offset += to_read;
        remain -= to_read;
		if(remain > 0)
			aos_msleep(10);
    }
    
	uint32_t inbuf_size = H2M_PACKET_HEADER_LEN + msg_data_size;

//	inbuf[temp]="\n";
//	LOGI(TAG,"n=%d\n", n);
//	LOGI(TAG,"len=%d, inbuf= %s \n", temp, inbuf);
	LOGI(TAG,"msgId=%d; size=%d\n", msgid, msg_data_size-1);
	
	if(!g_ifv_flow_cfg.sensetime_protocol_enable)
	{
		if(inbuf[inbuf_size-1] != get_check_sum(inbuf, inbuf_size-1))
		{
			LOGE(TAG,"check_parity failed \n");
			return 1;
		}
	}
	
	*rece_size = inbuf_size;
	return 0;
}

